package com.terrynoya.fight.commands
{
	import com.terrynoya.fight.emuns.CommandButton;
	import com.terrynoya.fight.emuns.CommandDirection;
	import com.terrynoya.fight.io.FileSystem;
	import com.terrynoya.fight.io.KeyValuePair;
	import com.terrynoya.fight.io.TextFile;
	import com.terrynoya.fight.io.TextSection;

	public class CommandSystem
	{
		public static const NUMBER_REG:RegExp = /(\\d+)/;
		public static const DEFAULT_COMMAND_TIME:int = 15;
		
		public function CommandSystem()
		{
			
		}
		
		public static function build(txt:String):Array
		{
			var commands:Array = new Array();
			var txtFile:TextFile = FileSystem.build(txt);
			for (var i:int = 0; i < txtFile.sections.length; i++) 
			{
				var section:TextSection = txtFile.sections[i];
				if(section.title != "Command")
				{
					continue;
				}
				var cmd:InputCommand = createCommand(section);
				commands.push(cmd);
			}
			return commands;
		}
		
		public static function createCommand(section:TextSection):InputCommand
		{
			var name:String = "";
			var elements:Array;
			var time:int = DEFAULT_COMMAND_TIME;
			var text:String = "";
			var bufferTime:int = 1;
			
			for (var i:int = 0; i < section.parsedLines.length; i++) 
			{
				var vo:KeyValuePair = section.parsedLines[i];
				switch(vo.key)
				{
					case "name":
					{
						var val:String = vo.value;
						name = val.substr(1,val.length - 2);
						break;
					}
					case "time":
					{
						time = int(vo.value);
						break;
					}
					case "command":
					{
						elements = createCommandElements(vo.value);
						text = vo.value;
						break;
					}
					case "Buffer.time":
					{
						bufferTime = int(vo.value);
						break;
					}
				}
			}
			
			var cmd:InputCommand = new InputCommand(name,text,time,bufferTime,elements);
			return cmd;
		}
		
		/**
		 * ~D, DF, F, D, DF, F, y
		 * @param txt
		 * 
		 */		
		public static function createCommandElements(txt:String):Array
		{
			var txtArr:Array = txt.split(",");
			var elements:Array = new Array();
			
			var lastElement:CommandElement = null;
			
			for (var i:int = 0; i < txtArr.length; i++) 
			{
				var token:String = txtArr[i];
				var ele:CommandElement = getCommandElement(token);
				if(lastElement != null && successiveDirectionCheck(lastElement,ele) == true)
				{
					var newelement1:CommandElement = new CommandElement(ele.direction, CommandButton.None, 0, false, true);
					var newelement2:CommandElement = new CommandElement(ele.direction, CommandButton.None, -1, false, true);
					
					elements.Add(newelement1);
					elements.Add(newelement2);
				}
				else
				{
					elements.push(ele);
				}
			}
			return elements;
		}
		
		private static function getCommandElement(token:String):CommandElement
		{
			var dir:int = CommandDirection.None;
			var buttons:int = CommandButton.None;
			
			var heldDown:Boolean = false;
			var nothingElse:Boolean = false;
			var triggerTime:int = -1;
			
			if(token.indexOf("~") != -1)
			{
				triggerTime = getReleaseTime(token);
			}
			
			if(token.indexOf("/") != -1) heldDown = true;
			if(token.indexOf(">") != -1) nothingElse = true;
			
			if (token.indexOf("$B") != -1) dir = CommandDirection.B4Way;
			else if (token.indexOf("$U") != -1) dir = CommandDirection.U4Way;
			else if (token.indexOf("$F") != -1) dir = CommandDirection.F4Way;
			else if (token.indexOf("$D") != -1) dir = CommandDirection.D4Way;
			else if (token.indexOf("DB") != -1) dir = CommandDirection.DB;
			else if (token.indexOf("DF") != -1) dir = CommandDirection.DF;
			else if (token.indexOf("UF") != -1) dir = CommandDirection.UF;
			else if (token.indexOf("UF") != -1) dir = CommandDirection.UF;
			else if (token.indexOf("D+B") != -1) dir = CommandDirection.DB;
			else if (token.indexOf("D+F") != -1) dir = CommandDirection.DF;
			else if (token.indexOf("U+B") != -1) dir = CommandDirection.UB;
			else if (token.indexOf("U+F") != -1) dir = CommandDirection.UF;
			else if (token.indexOf("D") != -1) dir = CommandDirection.D;
			else if (token.indexOf("F") != -1) dir = CommandDirection.F;
			else if (token.indexOf("U") != -1) dir = CommandDirection.U;
			else if (token.indexOf("B") != -1) dir = CommandDirection.B;
			
			if (token.indexOf("a") != -1) buttons |= CommandButton.A;
			if (token.indexOf("b") != -1) buttons |= CommandButton.B;
			if (token.indexOf("c") != -1) buttons |= CommandButton.C;
			if (token.indexOf("x") != -1) buttons |= CommandButton.X;
			if (token.indexOf("y") != -1) buttons |= CommandButton.Y;
			if (token.indexOf("z") != -1) buttons |= CommandButton.Z;
			if (token.indexOf("s") != -1) buttons |= CommandButton.Taunt;
			
			var ele:CommandElement = new CommandElement(dir,buttons,triggerTime,heldDown,nothingElse);
			return ele;
		}
		
		private static function getReleaseTime(token:String):int
		{
			if(!NUMBER_REG.test(token))
			{
				return 0;
			}
			var mathes:Array = token.match(NUMBER_REG);
			var time:int = mathes[1];
			return time;
		}
		
		private static function successiveDirectionCheck(last:CommandElement, now:CommandElement):Boolean
		{
			if (last != now) return false;
			if (last.direction == CommandDirection.None || last.direction == CommandDirection.B4Way || last.direction == CommandDirection.D4Way || last.direction == CommandDirection.F4Way || last.direction == CommandDirection.U4Way) return false;
			if (last.button != CommandButton.None || last.heldDown == true || last.nothingElse == true || last.triggerOnRelease == true) return false;
			return true;
		}
	}
}